Casting a base-class pointer/reference to a derived-class pointer/reference is commonly referred to as downcasting which can only be done
using an explicit cast.
However, the use of static_cast
for such a cast is unsafe because it doesn’t do any runtime check. If the cast memory doesn’t
contain an object of the expected derived type, your program enters the undefined behavior territory.
If your object is polymorphic, you might prefer using dynamic_cast
instead, as it allows safe downcasting by performing a run-time
check:
- If the cast memory contains an object of the expected derived type, the check succeeds. The result of the
dynamic_cast
points/refers to the derived object.
- If the cast memory doesn’t contain an object of the expected derived type, the check fails. If the
dynamic_cast
is used on a
pointer, nullptr
is returned. If it was used on a reference, std::bad_cast
is thrown.
This rule raises an issue when static_cast
is used for downcasting.
Noncompliant code example
struct Shape {
virtual ~Shape();
// ...
};
struct Rectangle : public Shape {
double width;
double height;
};
struct Circle : public Shape {
double radius;
};
double computeArea(const Shape* shape) {
const auto* rectangle = static_cast<const Rectangle*>(shape); // Noncompliant
return rectangle->width * rectangle->height;
}
Compliant solution
struct Shape {
virtual ~Shape();
// ...
};
struct Rectangle : public Shape {
double width;
double height;
};
struct Circle : public Shape {
int radius;
};
double computeArea(const Shape* shape) {
if(const auto* rectangle = dynamic_cast<const Rectangle*>(shape)) { // Compliant
return rectangle->width * rectangle->height;
}
return 0;
}